﻿using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using XcoAppSpaces.Core.Communication;
using Rhino.Mocks;
using XcoAppSpaces.Contracts.Serialization;
using XcoAppSpaces.Contracts.Exceptions;
using XcoAppSpaces.Core.Ports;

namespace test.XcoAppSpaces.Core.Communication
{
	[TestFixture]
	public class SerializableCheckTest
	{
		//test classes
		class ContractWith1MsgType : Port<string> { }
		class ContractWith3MsgTypes : PortSet<int, string, DateTime> { }
		class ContractWithResponsePorts : PortSet<MsgWithResponsePorts1, MsgWithResponsePorts2> { }
		class MsgWithResponsePorts1
		{
			public Port<ResponseMsg1> ResponsePort { get; set; }
			public Port<Exception> errorPort = new Port<Exception>();
		}
		class MsgWithResponsePorts2
		{
			public PortSet<ResponseMsg2, ResponseMsg3> ResponsePort { get; set; }
		}
		class ResponseMsg1 { }
		class ResponseMsg2 { }
		class ResponseMsg3 { }
		class ContractWithPortSetAsMessageType : PortSet<int, PortSet<string, DateTime>> { }
		
		private MockRepository mocks;
		private IXcoSerializer serializerMock;


		[SetUp]
		public void SetUp()
		{
			mocks = new MockRepository();
			serializerMock = mocks.StrictMock<IXcoSerializer>();
		}

		[TearDown]
		public void TearDown()
		{
			mocks.VerifyAll();
		}

		[Test]
		public void GetTypesForSerializationCheck_1MessageType()
		{
			mocks.ReplayAll();
			
			var types = SerializableCheck.GetTypesForSerializationCheck<ContractWith1MsgType>().ToArray();
			Assert.AreEqual(1, types.Length);
			Assert.AreEqual(typeof(string), types[0]);
		}

		[Test]
		public void GetTypesForSerializationCheck_3MessageTypes()
		{
			mocks.ReplayAll();
			
			var types = SerializableCheck.GetTypesForSerializationCheck<ContractWith3MsgTypes>().ToArray();
			Assert.AreEqual(3, types.Length);
			Assert.AreEqual(typeof(int), types[0]);
			Assert.AreEqual(typeof(string), types[1]);
			Assert.AreEqual(typeof(DateTime), types[2]);
		}

		[Test]
		public void GetTypesForSerializationCheck_ResponsePorts()
		{
			mocks.ReplayAll();
			
			var types = SerializableCheck.GetTypesForSerializationCheck<ContractWithResponsePorts>().ToArray();
			Assert.AreEqual(6, types.Length);
			Assert.AreEqual(typeof(MsgWithResponsePorts1), types[0]);
			Assert.AreEqual(typeof(MsgWithResponsePorts2), types[1]);
			Assert.AreEqual(typeof(Exception), types[2]);
			Assert.AreEqual(typeof(ResponseMsg1), types[3]);
			Assert.AreEqual(typeof(ResponseMsg2), types[4]);
			Assert.AreEqual(typeof(ResponseMsg3), types[5]);
		}

		[Test]
		public void GetTypesForSerializationCheck_ContractWithPortSetAsMsgType()
		{
			mocks.ReplayAll();

			var types = SerializableCheck.GetTypesForSerializationCheck<ContractWithPortSetAsMessageType>().ToArray();
			Assert.AreEqual(3, types.Length);
			Assert.AreEqual(typeof(int), types[0]);
			Assert.AreEqual(typeof(string), types[1]);
			Assert.AreEqual(typeof(DateTime), types[2]);
		}

		[Test]
		public void CheckIfMessageTypesCanBeSerialized_SerializerReturnsTrue()
		{
			string bla;
			Expect.Call(serializerMock.CanTypeBeSerialized(null, out bla)).IgnoreArguments().Return(true).Repeat.Times(3);
			mocks.ReplayAll();

			SerializableCheck.CheckIfMessageTypesCanBeSerialized<ContractWith3MsgTypes>(serializerMock);
		}

		[Test]
		[ExpectedException(typeof(XcoSerializationException))]
		public void CheckIfMessageTypesCanBeSerialized_SerializerReturnsFalse()
		{
			string bla;
			Expect.Call(serializerMock.CanTypeBeSerialized(null, out bla)).IgnoreArguments().Return(false).Repeat.Times(3);
			mocks.ReplayAll();

			SerializableCheck.CheckIfMessageTypesCanBeSerialized<ContractWith3MsgTypes>(serializerMock);
		}
	}
}
